#include "recepteur.h"
#include "reseau.h"
#include "commun/erreur.h"
#include "temps/weather_report.h"
#include "commun/instantane_du_piano.h"

/**
 * Construit un récepteur et alloue un paquet TCP.
 */
recepteur_reseau::recepteur_reseau(TCPsocket &chaussette_tcp, 
				 UDPsocket &chaussette_udp, 
				 SDLNet_SocketSet &assortiment) throw()
				:	chaussette_tcp_(chaussette_tcp), 
					chaussette_udp_(chaussette_udp),
					assortiment_de_chaussettes_(assortiment) {
	paquet_ = SDLNet_AllocPacket(TAILLE_BUFFER);
	if(!paquet_)
		throw une_erreur<allocation_paquet>();
}

/**
 * Reçoit un paquet TCP de manière asynchrone et place le résultat dans buffer.
 * buffer doit pouvoir accueillir TAILLE_BUFFER.
 */
bool recepteur_reseau::recevoir_tcp_asynchrone(void *buffer) {
	int n = SDLNet_CheckSockets(assortiment_de_chaussettes_, 0);
	if(n == -1)
		throw une_erreur<reception_socket>();
	else if(n > 0) {
		if(SDLNet_SocketReady(chaussette_tcp_)) {
			if(SDLNet_TCP_Recv(chaussette_tcp_, buffer, TAILLE_BUFFER) < 0)
				throw une_erreur<reception_socket>();
			return true;
		}
	}
	return false;
}

/**
 * Reçoit un paquet TCP de manière synchrone (buffer doit pouvoir contenir
 * TAILLE_BUFFER).
 */
void recepteur_reseau::recevoir_tcp(void *buffer) {
	if(SDLNet_TCP_Recv(chaussette_tcp_, buffer, TAILLE_BUFFER) < 0) {
		throw une_erreur<reception_socket>();
	}
}

/**
 * Reçoit un paquet quelconque et en tire le port de provenance (sur les ports
 * d'Amsterdam, y'a des marins qui chantent).
 * Attention, le port est encodé avec le network byte order !
 */
bool recepteur_reseau::recevoir_port_udp(Uint16 &prt) {
	int r = SDLNet_UDP_Recv(chaussette_udp_, paquet_);
	
	if(r == 0)
		return false;
	else if(r == -1)
		throw une_erreur<reception_socket>();
	
	prt = paquet_->address.port;
	return true;
}

/**
 * Reçoit un instantané du piano par UDP, mis dans s.
 */
bool recepteur_reseau::recevoir_udp(instantane_du_piano &s) {
	int r = SDLNet_UDP_Recv(chaussette_udp_, paquet_);
	
	if(r == 0 || (r == 1 && paquet_->len != sizeof(temps::type_temps) + instantane_du_piano::nb_octets))
		return false;
	else if(r == -1)
		throw une_erreur<reception_socket>();
	
	s.timestamp(SDLNet_Read32(paquet_->data + instantane_du_piano::nb_octets));
	s.initialiser(paquet_->data);
	
	return true;
}
